import java.time.Instant;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // somanyThread();
        // threadPoolTest();
        // threadCachePoolTest();
        scheduledThreadPoolTest();
    }

    public static void somanyThread() throws InterruptedException {
        Instant now = Instant.now();
        Thread[] arr = new Thread[1000];
        for (int i = 0; i < 1000; i++) {
            final int idx = i;
            arr[i] = new Thread(() -> {
                // System.out.println("第" + idx + "个:");
            });
            arr[i].start();
        }
        for (Thread t : arr)
            t.join(); // 等全部跑完
        Instant end = Instant.now();
        System.out.println("somanyThread  use : " + (end.toEpochMilli() - now.toEpochMilli()) + " ms");
    }

    // Java语言虽然内置了多线程支持，启动一个新线程非常方便，
    // 但是，创建线程需要操作系统资源（线程资源，栈空间等），频繁创建和销毁大量线程需要消耗大量时间和系统资源，影响程序性能。
    // 因此，Java标准库提供了线程池（Thread Pool）机制，
    // 通过复用线程池中的线程来执行多个任务，避免了频繁创建和销毁线程的开销，提高了程序的性能和响应速度。
    public static void threadPoolTest() throws InterruptedException {
        Instant now = Instant.now();
        ExecutorService es = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 1000; i++) {
            final int idx = i;
            es.submit(() -> {
                // System.out.println("第" + idx + "个:")
            });
        }
        // shutdown()方法关闭线程池的时候，它会等待正在执行的任务先完成，然后再关闭。
        // shutdownNow()会立刻停止正在执行的任务，
        // awaitTermination()则会等待指定的时间让线程池关闭
        // 不是“三选一”，而是两步必须配合：
        // 先 shutdown()
        // 告诉线程池“别再接新任务，把已提交的执行完”。
        // 再 awaitTermination(...)
        // 当前线程阻塞在这里，直到池内任务全部结束或超时。
        es.shutdown();
        es.awaitTermination(998, TimeUnit.MINUTES);
        Instant end = Instant.now();
        System.out.println("threadPoolTest use : " + (end.toEpochMilli() - now.toEpochMilli()) + " ms");
    }

    // CachedThreadPool，由于这个线程池的实现会根据任务数量动态调整线程池的大小
    public static void threadCachePoolTest() throws InterruptedException {
        Instant now = Instant.now();
        int corePoolSize = 4; // 核心线程数
        int maximumPoolSize = 10; // 最大线程数
        long keepAliveTime = 60L;
        TimeUnit unit = TimeUnit.SECONDS;
        // 工作队列（这里使用同步队列，和CachedThreadPool的默认队列一致）
        BlockingQueue<Runnable> workQueue = new SynchronousQueue<>();

        // 直接使用ThreadPoolExecutor创建线程池，而不是Executors的工厂方法
        ExecutorService es = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue);

        for (int i = 0; i < 1000; i++) {
            final int idx = i;
            es.submit(() -> {
                // 任务逻辑（可以添加一些耗时操作来观察线程池行为）
                // 例如：Thread.sleep(10);
            });
        }
        es.shutdown();
        es.awaitTermination(998, TimeUnit.MINUTES);
        Instant end = Instant.now();
        System.out.println("threadCachePoolTest use : " + (end.toEpochMilli() - now.toEpochMilli()) + " ms");
    }

    // ScheduledThreadPool
    // 还有一种任务，需要定期反复执行，例如，每秒刷新证券价格。这种任务本身固定，需要反复执行的
    public static void scheduledThreadPoolTest() throws InterruptedException {
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(4);
        // 1秒后执行一次性任务:
        ses.schedule(() -> {
            System.out.println("One-time task executed");
        }, 1, TimeUnit.SECONDS);
        // 2秒后开始执行定时任务，每3秒执行:
        ses.scheduleAtFixedRate(() -> {
            System.out.println("scheduleAtFixedRate task executed");
        }, 2, 3, TimeUnit.SECONDS);
        // 2秒后开始执行定时任务，以3秒为间隔执行:
        ses.scheduleWithFixedDelay(() -> {
            System.out.println("scheduleWithFixedDelay task executed");
        }, 2, 3, TimeUnit.SECONDS);

        // 注意FixedRate和FixedDelay的区别。FixedRate是指任务总是以固定时间间隔触发，不管任务执行多长时间：
        // 而FixedDelay是指，上一次任务执行完毕后，等待固定的时间间隔，再执行下一次任务：

        // 运行3秒后停止线程池
        Thread.sleep(3000);

        // 步骤1：关闭线程池（选择合适的方法）
        ses.shutdown(); // 等待现有任务完成后关闭（推荐用于需要优雅终止的场景）
        // 或使用 ses.shutdownNow(); // 立即停止所有任务（用于紧急终止）

        // 步骤2：等待线程池终止（最多等待1分钟）
        if (!ses.awaitTermination(1, TimeUnit.MINUTES)) {
            System.out.println("线程池未在指定时间内终止，可能需要强制关闭");
            // 若超时，可再次尝试shutdownNow()
            ses.shutdownNow();
        }

        System.out.println("线程池已完全终止");
    }

}
